local player = player

local ready = 0

function GM:PlayerInitialSpawn(ply)
	ply.dealt = 0

	timer.Create("SteamID", 1, 1, function()
		local SteamID = ply:SteamID()
		ply:SetNWString("SteamID", SteamID)
	end)
	
	ply.firstspawned = true
	ply.respawned = false
	
	if ply then
		ready = ready + 1
		SetGlobalFloat("ze_players", ready)
	end
	
	if ready < 3 then
		PlayerCheck()
	end
	
	ply.Class = nil
end

function GM:PlayerDisconnected(ply)
	ready = ready - 1
	SetGlobalFloat("ze_players", ready)
	
	WinCheck()
	
	if ready < 2 then
		PlayerCheck()
	end
end

function GM:PlayerSpawn(ply)
	-- if GetRoundState() > 2 then
		-- if not ply.firstspawned then
			-- ply:SetTeam(TEAM_SPEC)
		-- else
			-- ply:SetZombie()
		-- end
	-- else
		-- if not ply:IsBot() then
			-- if not ply.Class then
				-- MsgN(ply.Class)
				-- ply:KillSilent()
				-- ply:Freeze(true)
				-- ply:SetTeam(TEAM_SPEC)
				-- ply:Spectate(6)
				-- GAMEMODE:PlayerSpawnAsSpectator(ply)
				-- timer.Simple(0.5, function()
					-- ply:ConCommand("+class_menu")
				-- end)
			-- else
				-- ply:SetHuman()
			-- end
		-- else
			local classes = {CLASS_DEFAULT, CLASS_SUPPORT, CLASS_EVADER}
			ply.Class = classes[math.random(1, 3)]
			ply:UnSpectate()
			ply:SetHuman()
		-- end
	-- end
	
	if ply.firstspawned then
		ply.firstspawned = false
	end
	
	if ply.respawned then
		ply.respawned = false
	end
	
	-- if ply:IsSpec() and not (GetRoundState() < 3) then
	-- return end

	ply:UnSpectate()
end

function PlayerRespawn()
	for k, ply in pairs(player.GetAll()) do
		ply:SpawnRound()
	end
end

function GM:PlayerJoinTeam(ply)
	if GetRoundState() == STATE_ACTIVE then
		WinCheck()
	end
end

function GM:PlayerSetModel(ply)
	local model = ply.Class.PlayerModel
	ply:SetModel(model)
end

function GM:DoPlayerDeath(ply, attacker, dmginfo)
	if GetRoundState() > 2 then
		ply.Class = nil
		WinCheck()
	end

    ply:CreateRagdoll()
    
    ply:AddDeaths(1)
    
    if attacker:IsValid() and attacker:IsPlayer() then
        if attacker == ply then
            attacker:AddFrags(-1)
        else
            attacker:AddFrags(1)
        end
    end
	
	if ply:IsSpec() and not (GetRoundState() < 3) then 
	return end
end

function GM:PlayerDeath(ply, infl, attacker)

	ply:Freeze(true)
	ply:SetTeam(TEAM_SPEC)
	
	timer.Simple(5, function()
		if not ply:Alive() then
			ply:Freeze(false)

			GAMEMODE:PlayerSpawnAsSpectator(ply)
			ply:Spectate(6)
		end
	end)
end

function GM:SpectatorThink(ply)
	if (GetRoundState() > 2) then
	return end
	
	if (ply:KeyPressed(IN_ATTACK) or ply:KeyPressed(IN_ATTACK2) or ply:KeyPressed(IN_JUMP)) and ply.Class then
		ply:Spawn()
    end
end
GM.PlayerDeathThink = GM.SpectatorThink

function GM:CanPlayerSuicide(ply)
	return false
end

function GM:EntityTakeDamage(ent, inflictor, attacker, amount, dmginfo)
	if dmginfo:IsBulletDamage() and not ent:IsPlayer() then
		local direction = attacker:GetForward()
		local wep = attacker:GetActiveWeapon()
		
		ent:SetVelocity(direction * wep:GetKnockback() * Vector(0.75, 0.75, 0.5))
	end

	if ent:IsPlayer() then
		
		GAMEMODE:PlayerTakeDamage(ent, inflictor, attacker, amount, dmginfo)
		
	end
end

function GM:PlayerTakeDamage(ply, inflictor, attacker, amount, dmginfo)
	GAMEMODE:ScalePlayerDamage(ply, ply:LastHitGroup() or HITGROUP_GENERIC, dmginfo, true)

	if attacker:IsPlayer() then
		if ply:Team() == TEAM_ZOMBIE then
			if dmginfo:IsBulletDamage() then		
				attacker:AddDamageDealt(dmginfo)
			end
		elseif ply:Team() == TEAM_HUMAN then
			if attacker:Team() == TEAM_ZOMBIE then
				Infect(ply, attacker)
				WinCheck()
			end
		end
	end
end

function GM:PlayerTraceAttack(ply, dmginfo, dir, trace)
	if ply:IsZombie() and dmginfo:GetAttacker():IsHuman() and dmginfo:IsBulletDamage() then
		local wep = dmginfo:GetInflictor()
		local velpower = velpower
		
		local hitgroup = trace.HitGroup
		
		if hitgroup == HITGROUP_HEAD then
			velpower = Vector(2, 2, 0.5)
		else
			velpower = Vector(1, 1, 0.5)
		end

		local aircompens = ply:IsOnGround() and Vector(1, 1, 1) or Vector(0.5, 0.5, 0.5)

		if dmginfo:GetWeaponClass() == "sg" then
			local dist = ply:GetPos():Distance(dmginfo:GetAttacker():GetPos())
			local power = Lerp(dist/1024, wep:GetKnockback(), wep:GetKnockback()/4)
		
			ply:SetVelocity(dir * (power * velpower * aircompens))
		else
			ply:SetVelocity(dir * (wep:GetKnockback() * velpower * aircompens))
		end
	end
	return false
end

function GM:PlayerShouldTakeDamage(victim, attacker)
	if attacker:IsPlayer() then
		if victim:Team() == attacker:Team() then
			return false
		else
			return true
		end
	else return true
	end
end

function GM:ScalePlayerDamage(ply, hitgroup, dmginfo, real)
	if not real then return end

	dmginfo:SetDamage(dmginfo:GetBaseDamage()/2)

	if hitgroup == HITGROUP_HEAD then
	
		local wep = dmginfo:GetAttacker():GetActiveWeapon()
		
		if IsValid(wep) then
			dmginfo:ScaleDamage(1.5)
		end

	elseif (hitgroup == HITGROUP_LEFTARM or hitgroup == HITGROUP_RIGHTARM or hitgroup == HITGROUP_LEFTLEG or hitgroup == HITGROUP_RIGHTLEG or hitgroup == HITGROUP_GEAR) then
		dmginfo:ScaleDamage(0.75)
	end

	if dmginfo:IsDamageType(DMG_DIRECT) or
		dmginfo:IsExplosionDamage() or
		dmginfo:IsDamageType(DMG_FALL) or
		dmginfo:IsDamageType(DMG_PHYSGUN) then
		dmginfo:ScaleDamage(2)
	end
end

function GM:GetFallDamage(ply, speed)
	return 1
end

function Infect(ent, infector)
	if ent:Team() == TEAM_HUMAN then
		ent:SetZombie()
		
		ent:AddDeaths(1)
		infector:AddFrags(1)
		
		ent:EmitSound("npc/fast_zombie/fz_scream1.wav", 100)
		
		ZombieMsg(ent, "You have been infected by a zombie.")
	end
end

local fallsounds = {
	Sound("player/damage1.wav"),
	Sound("player/damage2.wav"),
	Sound("player/damage3.wav")
};

function GM:OnPlayerHitGround(ply, in_water, on_floater, speed)
	if in_water or speed < 450 or not IsValid(ply) then return end

	local damage = math.pow(0.05 * (speed - 420), 1.75)

	if on_floater then damage = damage / 2 end

	if math.floor(damage) > 0 then
		local dmg = DamageInfo()
		dmg:SetDamageType(DMG_FALL)
		dmg:SetAttacker(GetWorldEntity())
		dmg:SetInflictor(GetWorldEntity())
		dmg:SetDamageForce(Vector(0, 0, 1))
		dmg:SetDamage(damage)

		ply:TakeDamageInfo(dmg)

		if damage > 5 then
			WorldSound(table.Random(fallsounds), ply:GetShootPos(), 55 + math.Clamp(damage, 0, 50), 100)
		end
	end
end